/*
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

#include <systemd/sd-journal.h>
#include <unistd.h>

#include <OtrdCppLog.hpp>
#include <PSUInfo.hpp>
#include <PSUStatus.hpp>
#include <SensorPaths.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <gpiod.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>

#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <istream>
#include <limits>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <regex>
#include <stdexcept>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include <stdint.h>

using namespace std;

using EventData = std::map<uint8_t, std::map<uint8_t, std::vector<uint8_t>>>;
static constexpr uint16_t psuStatusPresent = 1;

static constexpr uint16_t psuStatusAbsent = 0;

static constexpr const char* modeNormal = "Normal";
static constexpr const char* modeActive = "Active";
static constexpr const char* modeStandby = "Standby";

IOut_Status::IOut_Status(
    const std::string& bus, const std::string& address,
    sdbusplus::asio::object_server& objectServer, const std::string& psuName,
    boost::asio::io_service& io,
    std::map<std::string, std::string> psuPresentGpio,
    boost::container::flat_map<std::string, std::shared_ptr<PSUInfo>>
        allPSUInfos) :
    allPSUInfos(std::move(allPSUInfos)),
    objServer(objectServer), psuName(psuName), waitTimer(io),
    psuPresentGpio(std::move(psuPresentGpio)), gpioFd(io)
{
    IOut_psuStatus = psuName + "_IOut";
    std::string filename;
    std::filesystem::path psupath;
    psupath = "/sys/bus/i2c/devices/" + bus + "-" + address + "/hwmon";
    if (std::filesystem::exists(psupath))
    {
        for (auto& str : std::filesystem::directory_iterator(psupath))
        {
            filename = str.path().filename();
        }
    }
    IOut_StatusBytePath =
        "/sys/kernel/debug/pmbus/" + filename + "/status0_iout";

    /* 防抖机制：三次状态防抖数值相同代表状态稳定，三次状态防抖数值初始化为0 */
    for (int i = 0; i < PSU_OIS_STATUS_COUNT; i++)
    {
        IOut_statusByteOis.emplace_back(0); // statusWord防抖
    }

    std::string psuStatusPath = "/xyz/openbmc_project/State/" + IOut_psuStatus;
    std::string psuStatusInterface = "Status";

    IOut_psustatusInterface =
        objServer.add_interface(psuStatusPath, "com.otrd.Sensor.Status");

    uint8_t statusByte = 0x00;
    IOut_psustatusInterface->register_property("Value", statusByte);
    IOut_psustatusInterface->initialize();

    IOut_setupRead();
}

IOut_Status::~IOut_Status()
{
    waitTimer.cancel();
}

void IOut_Status::IOut_getStatusByte(void)
{
    std::string response;
    std::ifstream responseStream(IOut_StatusBytePath);
    uint8_t tmpStatusByte = 0;

    try
    {
        std::getline(responseStream, response);

        /* 防抖机制：2s(pollMs)内检测3次，三次状态防抖数值一样确认状态 */
        tmpStatusByte = std::stoi(response, nullptr, 16);
        IOut_statusByteOisIndex =
            ((IOut_statusByteOisIndex >= PSU_OIS_STATUS_COUNT)
                 ? 0
                 : IOut_statusByteOisIndex); // 防抖索引下标值迭代变化
        IOut_statusByteOis[IOut_statusByteOisIndex++] = tmpStatusByte;

        auto statusChange = 0;
        auto statusValue = IOut_statusByteOis[0];
        for (auto i : IOut_statusByteOis)
        {
            if (i != statusValue) // 状态发生改变
            {
                std::cerr << "IOut_psuStatus = " << IOut_psuStatus.c_str()
                          << ", IOut_statusByteOisIndex = "
                          << (IOut_statusByteOisIndex - 1) << "\n";
                std::cerr << "IOut_statusByteOis[0] = " << statusValue
                          << ", i = " << i << "\n";
                statusChange = 1;
                break;
            }

            continue;
        }

        /* 三次防抖状态值一样，代表状态稳定，进行赋值，否则代表状态发生变化，不做赋值操作
         */
        if (0 == statusChange)
        {
            IOut_StatusByte = tmpStatusByte;
        }

        responseStream.clear();
    }
    catch (const std::invalid_argument&)
    {
        std::cout << "Error parsing getStatusByte by path: "
                  << IOut_StatusBytePath << "\n";
    }
}

void IOut_Status::IOut_updateStatusByte(void)
{
    if (IOut_StatusByte == IOut_LastStatusByte)
    {
        return;
    }

    // auto it = IOut_statusByteMap.find(IOut_StatusByte);
    for (auto& [key, value] : IOut_statusByteMap)
    {
        if (!(IOut_LastStatusByte & key) && (IOut_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_WARNING,
                                    "%s  IOut Status:0x%02x-%s assert",
                                    psuName.c_str(), IOut_StatusByte,
                                    value.c_str());
        }
        else if ((IOut_LastStatusByte & key) && !(IOut_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_INFO,
                                    "%s IOut Status:0x%02x-%s deassert",
                                    psuName.c_str(), IOut_StatusByte,
                                    value.c_str());
        }
    }

    IOut_LastStatusByte = IOut_StatusByte;
    uint8_t statusByte = IOut_LastStatusByte;
    IOut_psustatusInterface->set_property("Value", statusByte);
}

void IOut_Status::IOut_handleResponse(void)
{
    IOut_updateStatusByte();
    waitTimer.expires_from_now(boost::posix_time::milliseconds(pollMs));
    waitTimer.async_wait([&](const boost::system::error_code& ec) {
        if (ec == boost::asio::error::operation_aborted)
        {
            return;
        }
        IOut_setupRead();
    });
}

void IOut_Status::IOut_setupRead(void)
{
    IOut_getStatusByte();
    IOut_handleResponse();
}

uint8_t IOut_Status::getValue(void) const
{
    return IOut_LastStatusByte;
}

VOut_Status::VOut_Status(
    const std::string& bus, const std::string& address,
    sdbusplus::asio::object_server& objectServer, const std::string& psuName,
    boost::asio::io_service& io,
    std::map<std::string, std::string> psuPresentGpio,
    boost::container::flat_map<std::string, std::shared_ptr<PSUInfo>>
        allPSUInfos) :
    allPSUInfos(std::move(allPSUInfos)),
    objServer(objectServer), psuName(psuName), waitTimer(io),
    psuPresentGpio(std::move(psuPresentGpio)), gpioFd(io)
{
    VOut_psuStatus = psuName + "_VOut";
    std::string filename;
    std::filesystem::path psupath;
    psupath = "/sys/bus/i2c/devices/" + bus + "-" + address + "/hwmon";
    if (std::filesystem::exists(psupath))
    {
        for (auto& str : std::filesystem::directory_iterator(psupath))
        {
            filename = str.path().filename();
        }
    }
    VOut_StatusBytePath =
        "/sys/kernel/debug/pmbus/" + filename + "/status0_vout";

    /* 防抖机制：三次状态防抖数值相同代表状态稳定，三次状态防抖数值初始化为0 */
    for (int i = 0; i < PSU_OIS_STATUS_COUNT; i++)
    {
        VOut_statusByteOis.emplace_back(0); // statusWord防抖
    }

    std::string psuStatusPath = "/xyz/openbmc_project/State/" + VOut_psuStatus;
    std::string psuStatusInterface = "Status";

    VOut_psustatusInterface =
        objServer.add_interface(psuStatusPath, "com.otrd.Sensor.Status");

    uint8_t statusByte = 0x00;
    VOut_psustatusInterface->register_property("Value", statusByte);
    VOut_psustatusInterface->initialize();

    VOut_setupRead();
}

VOut_Status::~VOut_Status()
{
    waitTimer.cancel();
}

void VOut_Status::VOut_getStatusByte(void)
{
    std::string response;
    std::ifstream responseStream(VOut_StatusBytePath);
    uint8_t tmpStatusByte = 0;

    try
    {
        std::getline(responseStream, response);

        /* 防抖机制：2s(pollMs)内检测3次，三次状态防抖数值一样确认状态 */
        tmpStatusByte = std::stoi(response, nullptr, 16);
        VOut_statusByteOisIndex =
            ((VOut_statusByteOisIndex >= PSU_OIS_STATUS_COUNT)
                 ? 0
                 : VOut_statusByteOisIndex); // 防抖索引下标值迭代变化
        VOut_statusByteOis[VOut_statusByteOisIndex++] = tmpStatusByte;

        auto statusChange = 0;
        auto statusValue = VOut_statusByteOis[0];
        for (auto i : VOut_statusByteOis)
        {
            if (i != statusValue) // 状态发生改变
            {
                std::cerr << "VOut_psuStatus = " << VOut_psuStatus.c_str()
                          << ", VOut_statusByteOisIndex = "
                          << (VOut_statusByteOisIndex - 1) << "\n";
                std::cerr << "VOut_statusByteOis[0] = " << statusValue
                          << ", i = " << i << "\n";
                statusChange = 1;
                break;
            }

            continue;
        }

        /* 三次防抖状态值一样，代表状态稳定，进行赋值，否则代表状态发生变化，不做赋值操作
         */
        if (0 == statusChange)
        {
            VOut_StatusByte = tmpStatusByte;
        }

        responseStream.clear();
    }
    catch (const std::invalid_argument&)
    {
        std::cout << "Error parsing getStatusByte by path: "
                  << VOut_StatusBytePath << "\n";
    }
}

void VOut_Status::VOut_updateStatusByte(void)
{
    if (VOut_StatusByte == VOut_LastStatusByte)
    {
        return;
    }

    for (auto& [key, value] : VOut_statusByteMap)
    {
        if (!(VOut_LastStatusByte & key) && (VOut_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_WARNING,
                                    "%s VOut Status:0x%02x-%s assert",
                                    psuName.c_str(), VOut_StatusByte,
                                    value.c_str());
        }
        else if ((VOut_LastStatusByte & key) && !(VOut_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_INFO,
                                    "%s VOut Status:0x%02x-%s deassert",
                                    psuName.c_str(), VOut_StatusByte,
                                    value.c_str());
        }
    }

    VOut_LastStatusByte = VOut_StatusByte;
    uint8_t statusByte = VOut_LastStatusByte;
    VOut_psustatusInterface->set_property("Value", statusByte);
}

void VOut_Status::VOut_handleResponse(void)
{
    VOut_updateStatusByte();
    waitTimer.expires_from_now(boost::posix_time::milliseconds(pollMs));
    waitTimer.async_wait([&](const boost::system::error_code& ec) {
        if (ec == boost::asio::error::operation_aborted)
        {
            return;
        }
        VOut_setupRead();
    });
}

void VOut_Status::VOut_setupRead(void)
{
    VOut_getStatusByte();
    VOut_handleResponse();
}

uint8_t VOut_Status::getValue(void) const
{
    return VOut_LastStatusByte;
}

Input_Status::Input_Status(
    const std::string& bus, const std::string& address,
    sdbusplus::asio::object_server& objectServer, const std::string& psuName,
    boost::asio::io_service& io,
    std::map<std::string, std::string> psuPresentGpio,
    boost::container::flat_map<std::string, std::shared_ptr<PSUInfo>>
        allPSUInfos) :
    allPSUInfos(std::move(allPSUInfos)),
    objServer(objectServer), psuName(psuName), waitTimer(io),
    psuPresentGpio(std::move(psuPresentGpio)), gpioFd(io)
{
    Input_psuStatus = psuName + "_Input";
    std::string filename;
    std::filesystem::path psupath;
    psupath = "/sys/bus/i2c/devices/" + bus + "-" + address + "/hwmon";
    if (std::filesystem::exists(psupath))
    {
        for (auto& str : std::filesystem::directory_iterator(psupath))
        {
            filename = str.path().filename();
        }
    }
    Input_StatusBytePath =
        "/sys/kernel/debug/pmbus/" + filename + "/status0_input";

    /* 防抖机制：三次状态防抖数值相同代表状态稳定，三次状态防抖数值初始化为0 */
    for (int i = 0; i < PSU_OIS_STATUS_COUNT; i++)
    {
        Input_statusByteOis.emplace_back(0); // statusWord防抖
    }

    std::string psuStatusPath = "/xyz/openbmc_project/State/" + Input_psuStatus;
    std::string psuStatusInterface = "Status";

    Input_psustatusInterface =
        objServer.add_interface(psuStatusPath, "com.otrd.Sensor.Status");

    uint8_t statusByte = 0x00;
    Input_psustatusInterface->register_property("Value", statusByte);
    Input_psustatusInterface->initialize();

    Input_setupRead();
}

Input_Status::~Input_Status()
{
    waitTimer.cancel();
}

void Input_Status::Input_getStatusByte(void)
{
    std::string response;
    std::ifstream responseStream(Input_StatusBytePath);
    uint8_t tmpStatusByte = 0;

    try
    {
        std::getline(responseStream, response);

        /* 防抖机制：2s(pollMs)内检测3次，三次状态防抖数值一样确认状态 */
        tmpStatusByte = std::stoi(response, nullptr, 16);
        Input_statusByteOisIndex =
            ((Input_statusByteOisIndex >= PSU_OIS_STATUS_COUNT)
                 ? 0
                 : Input_statusByteOisIndex); // 防抖索引下标值迭代变化
        Input_statusByteOis[Input_statusByteOisIndex++] = tmpStatusByte;

        auto statusChange = 0;
        auto statusValue = Input_statusByteOis[0];
        for (auto i : Input_statusByteOis)
        {
            if (i != statusValue) // 状态发生改变
            {
                std::cerr << "Input_psuStatus = " << Input_psuStatus.c_str()
                          << ", Input_statusByteOisIndex = "
                          << (Input_statusByteOisIndex - 1) << "\n";
                std::cerr << "Input_statusByteOis[0] = " << statusValue
                          << ", i = " << i << "\n";
                statusChange = 1;
                break;
            }

            continue;
        }

        /* 三次防抖状态值一样，代表状态稳定，进行赋值，否则代表状态发生变化，不做赋值操作
         */
        if (0 == statusChange)
        {
            Input_StatusByte = tmpStatusByte;
        }

        responseStream.clear();
    }
    catch (const std::invalid_argument&)
    {
        std::cout << "Error parsing getStatusByte by path: "
                  << Input_StatusBytePath << "\n";
    }
}

void Input_Status::Input_updateStatusByte(void)
{
    if (Input_StatusByte == Input_LastStatusByte)
    {
        return;
    }

    // auto it = Input_statusByteMap.find(Input_StatusByte);
    for (auto& [key, value] : Input_statusByteMap)
    {
        if (!(Input_LastStatusByte & key) && (Input_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_WARNING,
                                    "%s  Input Status:0x%02x-%s assert",
                                    psuName.c_str(), Input_StatusByte,
                                    value.c_str());
        }
        else if ((Input_LastStatusByte & key) && !(Input_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_INFO,
                                    "%s Input Status:0x%02x-%s deassert",
                                    psuName.c_str(), Input_StatusByte,
                                    value.c_str());
        }
    }

    Input_LastStatusByte = Input_StatusByte;
    uint8_t statusByte = Input_LastStatusByte;
    Input_psustatusInterface->set_property("Value", statusByte);
}

void Input_Status::Input_handleResponse(void)
{
    Input_updateStatusByte();
    waitTimer.expires_from_now(boost::posix_time::milliseconds(pollMs));
    waitTimer.async_wait([&](const boost::system::error_code& ec) {
        if (ec == boost::asio::error::operation_aborted)
        {
            return;
        }
        Input_setupRead();
    });
}

void Input_Status::Input_setupRead(void)
{
    Input_getStatusByte();
    Input_handleResponse();
}

uint8_t Input_Status::getValue(void) const
{
    return Input_LastStatusByte;
}

OTP_Status::OTP_Status(
    const std::string& bus, const std::string& address,
    sdbusplus::asio::object_server& objectServer, const std::string& psuName,
    boost::asio::io_service& io,
    std::map<std::string, std::string> psuPresentGpio,
    boost::container::flat_map<std::string, std::shared_ptr<PSUInfo>>
        allPSUInfos) :
    allPSUInfos(std::move(allPSUInfos)),
    objServer(objectServer), psuName(psuName), waitTimer(io),
    psuPresentGpio(std::move(psuPresentGpio)), gpioFd(io)
{
    OTP_psuStatus = psuName + "_OTP";
    std::string filename;
    std::filesystem::path psupath;
    psupath = "/sys/bus/i2c/devices/" + bus + "-" + address + "/hwmon";
    if (std::filesystem::exists(psupath))
    {
        for (auto& str : std::filesystem::directory_iterator(psupath))
        {
            filename = str.path().filename();
        }
    }
    OTP_StatusBytePath =
        "/sys/kernel/debug/pmbus/" + filename + "/status0_temp";

    /* 防抖机制：三次状态防抖数值相同代表状态稳定，三次状态防抖数值初始化为0 */
    for (int i = 0; i < PSU_OIS_STATUS_COUNT; i++)
    {
        OTP_statusByteOis.emplace_back(0); // statusWord防抖
    }

    std::string psuStatusPath = "/xyz/openbmc_project/State/" + OTP_psuStatus;
    std::string psuStatusInterface = "Status";

    OTP_psustatusInterface =
        objServer.add_interface(psuStatusPath, "com.otrd.Sensor.Status");

    uint8_t statusByte = 0x00;
    OTP_psustatusInterface->register_property("Value", statusByte);
    OTP_psustatusInterface->initialize();

    OTP_setupRead();
}

OTP_Status::~OTP_Status()
{
    waitTimer.cancel();
}

void OTP_Status::OTP_getStatusByte(void)
{
    std::string response;
    std::ifstream responseStream(OTP_StatusBytePath);
    uint8_t tmpStatusByte = 0;

    try
    {
        std::getline(responseStream, response);

        /* 防抖机制：2s(pollMs)内检测3次，三次状态防抖数值一样确认状态 */
        tmpStatusByte = std::stoi(response, nullptr, 16);
        OTP_statusByteOisIndex =
            ((OTP_statusByteOisIndex >= PSU_OIS_STATUS_COUNT)
                 ? 0
                 : OTP_statusByteOisIndex); // 防抖索引下标值迭代变化
        OTP_statusByteOis[OTP_statusByteOisIndex++] = tmpStatusByte;

        auto statusChange = 0;
        auto statusValue = OTP_statusByteOis[0];
        for (auto i : OTP_statusByteOis)
        {
            if (i != statusValue) // 状态发生改变
            {
                std::cerr << "OTP_psuStatus = " << OTP_psuStatus.c_str()
                          << ", OTP_statusByteOisIndex = "
                          << (OTP_statusByteOisIndex - 1) << "\n";
                std::cerr << "OTP_statusByteOis[0] = " << statusValue
                          << ", i = " << i << "\n";
                statusChange = 1;
                break;
            }

            continue;
        }

        /* 三次防抖状态值一样，代表状态稳定，进行赋值，否则代表状态发生变化，不做赋值操作
         */
        if (0 == statusChange)
        {
            OTP_StatusByte = tmpStatusByte;
        }

        responseStream.clear();
    }
    catch (const std::invalid_argument&)
    {
        std::cout << "Error parsing getStatusByte by path: "
                  << OTP_StatusBytePath << "\n";
    }
}

void OTP_Status::OTP_updateStatusByte(void)
{
    if (OTP_StatusByte == OTP_LastStatusByte)
    {
        return;
    }

    // auto it = Input_statusByteMap.find(Input_StatusByte);
    for (auto& [key, value] : OTP_statusByteMap)
    {
        if (!(OTP_LastStatusByte & key) && (OTP_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_WARNING,
                                    "%s  Temperature Status:0x%02x-%s assert",
                                    psuName.c_str(), OTP_StatusByte,
                                    value.c_str());
        }
        else if ((OTP_LastStatusByte & key) && !(OTP_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_INFO,
                                    "%s Temperature Status:0x%02x-%s deassert",
                                    psuName.c_str(), OTP_StatusByte,
                                    value.c_str());
        }
    }

    OTP_LastStatusByte = OTP_StatusByte;
    uint8_t statusByte = OTP_LastStatusByte;
    OTP_psustatusInterface->set_property("Value", statusByte);
}

void OTP_Status::OTP_handleResponse(void)
{
    OTP_updateStatusByte();
    waitTimer.expires_from_now(boost::posix_time::milliseconds(pollMs));
    waitTimer.async_wait([&](const boost::system::error_code& ec) {
        if (ec == boost::asio::error::operation_aborted)
        {
            return;
        }
        OTP_setupRead();
    });
}

void OTP_Status::OTP_setupRead(void)
{
    OTP_getStatusByte();
    OTP_handleResponse();
}

uint8_t OTP_Status::getValue(void) const
{
    return OTP_LastStatusByte;
}

Fan12_Status::Fan12_Status(
    const std::string& bus, const std::string& address,
    sdbusplus::asio::object_server& objectServer, const std::string& psuName,
    boost::asio::io_service& io,
    std::map<std::string, std::string> psuPresentGpio,
    boost::container::flat_map<std::string, std::shared_ptr<PSUInfo>>
        allPSUInfos) :
    allPSUInfos(std::move(allPSUInfos)),
    objServer(objectServer), psuName(psuName), waitTimer(io),
    psuPresentGpio(std::move(psuPresentGpio)), gpioFd(io)
{
    Fan12_psuStatus = psuName + "_Fan12";
    std::string filename;
    std::filesystem::path psupath;
    psupath = "/sys/bus/i2c/devices/" + bus + "-" + address + "/hwmon";
    if (std::filesystem::exists(psupath))
    {
        for (auto& str : std::filesystem::directory_iterator(psupath))
        {
            filename = str.path().filename();
        }
    }
    Fan12_StatusBytePath =
        "/sys/kernel/debug/pmbus/" + filename + "/status0_fan12";

    /* 防抖机制：三次状态防抖数值相同代表状态稳定，三次状态防抖数值初始化为0 */
    for (int i = 0; i < PSU_OIS_STATUS_COUNT; i++)
    {
        Fan12_statusByteOis.emplace_back(0); // statusWord防抖
    }

    std::string psuStatusPath = "/xyz/openbmc_project/State/" + Fan12_psuStatus;
    std::string psuStatusInterface = "Status";

    Fan12_psustatusInterface =
        objServer.add_interface(psuStatusPath, "com.otrd.Sensor.Status");

    uint8_t statusByte = 0x00;
    Fan12_psustatusInterface->register_property("Value", statusByte);
    EventData edValue{};
    Fan12_psustatusInterface->register_property("EventData", edValue);

    Fan12_psustatusInterface->initialize();

    Fan12_setupRead();
}

Fan12_Status::~Fan12_Status()
{
    waitTimer.cancel();
}

void Fan12_Status::Fan12_getStatusByte(void)
{
    std::string response;
    std::ifstream responseStream(Fan12_StatusBytePath);
    uint8_t tmpStatusByte = 0;

    try
    {
        std::getline(responseStream, response);

        /* 防抖机制：2s(pollMs)内检测3次，三次状态防抖数值一样确认状态 */
        tmpStatusByte = std::stoi(response, nullptr, 16);
        Fan12_statusByteOisIndex =
            ((Fan12_statusByteOisIndex >= PSU_OIS_STATUS_COUNT)
                 ? 0
                 : Fan12_statusByteOisIndex); // 防抖索引下标值迭代变化
        Fan12_statusByteOis[Fan12_statusByteOisIndex++] = tmpStatusByte;

        auto statusChange = 0;
        auto statusValue = Fan12_statusByteOis[0];
        for (auto i : Fan12_statusByteOis)
        {
            if (i != statusValue) // 状态发生改变
            {
                std::cerr << "Fan12_psuStatus = " << Fan12_psuStatus.c_str()
                          << ", Fan12_statusByteOisIndex = "
                          << (Fan12_statusByteOisIndex - 1) << "\n";
                std::cerr << "Fan12_statusByteOis[0] = " << statusValue
                          << ", i = " << i << "\n";
                statusChange = 1;
                break;
            }

            continue;
        }

        /* 三次防抖状态值一样，代表状态稳定，进行赋值，否则代表状态发生变化，不做赋值操作
         */
        if (0 == statusChange)
        {
            Fan12_StatusByte = tmpStatusByte;
        }

        responseStream.clear();
    }
    catch (const std::invalid_argument&)
    {
        std::cout << "Error parsing getStatusByte by path: "
                  << Fan12_StatusBytePath << "\n";
    }
}

void Fan12_Status::Fan12_updateStatusByte(void)
{
    if (Fan12_StatusByte == Fan12_LastStatusByte)
    {
        return;
    }

    // auto it = Fan12_statusByteMap.find(Fan12_StatusByte);
    for (auto& [key, value] : Fan12_statusByteMap)
    {
        if (!(Fan12_LastStatusByte & key) && (Fan12_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_WARNING,
                                    "%s  Fan12 Status:0x%02x-%s assert",
                                    psuName.c_str(), Fan12_StatusByte,
                                    value.c_str());
        }
        else if ((Fan12_LastStatusByte & key) && !(Fan12_StatusByte & key))
        {
            OtrdCppMaintenanceLog(OtrdLogSeverity::LOG_LEVEL_INFO,
                                    "%s Fan12 Status:0x%02x-%s deassert",
                                    psuName.c_str(), Fan12_StatusByte,
                                    value.c_str());
        }
    }

    Fan12_LastStatusByte = Fan12_StatusByte;
    uint8_t statusByte = Fan12_LastStatusByte;
    Fan12_psustatusInterface->set_property("Value", statusByte);
    EventData edValue{{statusByte, {}}};
    Fan12_psustatusInterface->set_property("EventData", edValue);
}

void Fan12_Status::Fan12_handleResponse(void)
{
    Fan12_updateStatusByte();
    waitTimer.expires_from_now(boost::posix_time::milliseconds(pollMs));
    waitTimer.async_wait([&](const boost::system::error_code& ec) {
        if (ec == boost::asio::error::operation_aborted)
        {
            return;
        }
        Fan12_setupRead();
    });
}

void Fan12_Status::Fan12_setupRead(void)
{
    Fan12_getStatusByte();
    Fan12_handleResponse();
}

uint8_t Fan12_Status::getValue(void) const
{
    return Fan12_LastStatusByte;
}

PSUStatus::PSUStatus(
    const std::string& bus, const std::string& address,
    sdbusplus::asio::object_server& objectServer, const std::string& psuName,
    boost::asio::io_service& io,
    boost::container::flat_map<std::string, std::shared_ptr<PSUPresent>>
        psuPresent,
    std::shared_ptr<PSUInfo>& psuinfo,
    boost::container::flat_map<std::string, std::shared_ptr<IOut_Status>>
        psuIoutStatus,
    boost::container::flat_map<std::string, std::shared_ptr<VOut_Status>>
        psuVoutStatus,
    boost::container::flat_map<std::string, std::shared_ptr<Input_Status>>
        psuInputStatus,
    boost::container::flat_map<std::string, std::shared_ptr<OTP_Status>>
        psuOtpStatus,
    boost::container::flat_map<std::string, std::shared_ptr<Fan12_Status>>
        psuFan12Status) :
    objServer(objectServer),
    psuName(psuName), waitTimer(io), psuPresent(std::move(psuPresent)),
    psuinfo(psuinfo),
    psuIoutStatus(std::move(psuIoutStatus)),
    psuVoutStatus(std::move(psuVoutStatus)),
    psuInputStatus(std::move(psuInputStatus)),
    psuOtpStatus(std::move(psuOtpStatus)),
    psuFan12Status(std::move(psuFan12Status))
{
    psuStatus = psuName + "_Status";
    std::string filename;
    std::filesystem::path psupath;
    psupath = "/sys/bus/i2c/devices/" + bus + "-" + address + "/hwmon";
    if (std::filesystem::exists(psupath))
    {
        for (auto& str : std::filesystem::directory_iterator(psupath))
        {
            filename = str.path().filename();
        }
    }
    StatusWordPath = "/sys/kernel/debug/pmbus/" + filename + "/status0";
    blackboxReadPath =
        psupath.string() + "/" + filename + "/psu_history_fault_info";

    /* 防抖机制：三次状态防抖数值相同代表状态稳定，三次状态防抖数值初始化为0 */
    for (int i = 0; i < PSU_OIS_STATUS_COUNT; i++)
    {
        statusWordOis.emplace_back(0); // statusWord防抖
    }

    std::string psuStatusPath = "/xyz/openbmc_project/State/" + psuStatus;
    std::string psuStatusInterface = "Status";

    psustatusInterface =
        objServer.add_interface(psuStatusPath, "com.otrd.Sensor.Status");

    psustatussensorinterface = 
        objServer.add_interface(psuStatusPath, "xyz.openbmc_project.Sensor.Value");

    uint16_t statusWord = 0x00;
    psustatusInterface->register_property("StatusWord", statusWord);

    EventData edValue = {{0, {}}};
    psustatusInterface->register_property("EventData", edValue);
    psustatusInterface->initialize();
    psustatusDiagIntf =
        objectServer.add_interface(psuStatusPath, "com.otrd.Sensor.DiagInfo");
    psustatusDiagIntf->register_property<std::string>(
        "AlertSource", "", sdbusplus::asio::PropertyPermission::readWrite);
    psustatusDiagIntf->register_property<std::string>(
        "DeviceSN", psuinfo->psuSerialNum,
        sdbusplus::asio::PropertyPermission::readWrite);
    psustatusDiagIntf->register_property<std::string>(
        "Location", psuName, sdbusplus::asio::PropertyPermission::readWrite);
    psustatusDiagIntf->register_property<std::string>(
        "MsgAddInfo", "", sdbusplus::asio::PropertyPermission::readWrite);
    psustatusDiagIntf->initialize();

    addPsuWorkMode2DBus(filename);
    addPsuInputType2DBus(filename);
    // getPsuPresent();
    setupRead();
}

PSUStatus::~PSUStatus()
{
    waitTimer.cancel();
}

void PSUStatus::getPsuPresent(void)
{
    if (psuPresent[psuName])
    {
        Present = psuPresent[psuName]->getValue();
        if (Present == lastPresent)
        {
            return;
        }
        lastPresent = Present;
        if (Present)
        {
            EventData edValue = {{0, {}}};
            psustatusInterface->set_property("EventData", edValue);
        }
        else
        {
            EventData edValue = {};
            psustatusInterface->set_property("EventData", edValue);
            uint16_t statusAbsent = 0x0000;
            psustatusInterface->set_property("StatusWord", statusAbsent);
        }
    }
}

void PSUStatus::getStatusWord(void)
{
    std::string response;
    std::ifstream responseStream(StatusWordPath);
    uint16_t tmpStatusWord = 0;

    try
    {
        std::getline(responseStream, response);

        /* 防抖机制：2s(pollMs)内检测3次，三次状态防抖数值一样确认状态 */
        tmpStatusWord = std::stoi(response, nullptr, 16);
        statusWordOisIndex =
            ((statusWordOisIndex >= PSU_OIS_STATUS_COUNT)
                 ? 0
                 : statusWordOisIndex); //防抖索引下标值迭代变化
        statusWordOis[statusWordOisIndex++] = tmpStatusWord;

        auto statusChange = 0;
        auto statusValue = statusWordOis[0];
        for (auto i : statusWordOis)
        {
            if (i != statusValue) //状态发生改变
            {
                std::cerr << "psuStatus = " << psuStatus.c_str()
                          << ", statusWordOisIndex = "
                          << (statusWordOisIndex - 1) << "\n";
                std::cerr << "statusWordOis[0] = " << statusValue
                          << ", i = " << i << "\n";
                statusChange = 1;
                break;
            }

            continue;
        }

        /* 三次防抖状态值一样，代表状态稳定，进行赋值，否则代表状态发生变化，不做赋值操作
         */
        if (0 == statusChange)
        {
            StatusWord = tmpStatusWord;
        }

        responseStream.clear();
    }
    catch (const std::invalid_argument&)
    {
        std::cerr << "Error parsing getStatusWord by path: " << StatusWordPath
                  << "\n";
    }
}

void PSUStatus::updateBlackboxRecord(void)
{
    constexpr const char* blackboxLogFie = "/var/lib/log/psuFaultHistory.log";

    // access driver to get raw data
    int retry = 0;
    size_t page0Size = 0;
    size_t page1Size = 0;
    size_t page2Size = 0;
    std::string rawdata;

    for (retry = 0; retry < 3; retry++)
    {
        std::ifstream ifdriver(blackboxReadPath.c_str(), std::ios::in);
        if (ifdriver.good())
        {
            std::getline(ifdriver, rawdata);
            ifdriver.close();
        }
        else
        {
            std::cerr << "Fail to access driver device: " << blackboxReadPath
                      << std::endl;
            continue;
        }
        std::cout << "psu blackbox raw data: " << rawdata << std::endl;

        if (rawdata.find("page-0") != std::string::npos)
        {
            std::cout << "find page 0" << std::endl;
        }
        if (rawdata.find("page-1") != std::string::npos)
        {
            std::cout << "find page 1" << std::endl;
            page0Size = rawdata.find("page-1") - 1;
        }
        if (rawdata.find("page-2") != std::string::npos)
        {
            std::cout << "find page 2" << std::endl;
            page1Size = rawdata.find("page-2") - rawdata.find("page-1");
            page2Size = rawdata.length() - rawdata.find("page-2");
        }
        if ((0 == page0Size) || (0 == page1Size) || (0 == page2Size))
        {
            std::cerr << "Invalid blackbox data, page size is 0!" << std::endl;
            continue;
        }
        break;
    }
    if (retry >= 3)
    {
        std::cerr << "Failed to get blackbox data from driver!" << std::endl;
        return;
    }

    for (retry = 0; retry < 3; retry++)
    {
        std::ifstream ifpsu(blackboxLogFie, std::ios::in);
        if (!ifpsu.good())
        {
            std::cout << "need to create psu blackbox log file." << std::endl;
            std::ofstream ofpsu(blackboxLogFie, std::ios::out);
            if (ofpsu.good())
            {
                std::string page;
                page = psuName + ", " + rawdata.substr(0, page0Size);
                ofpsu << page;
                ofpsu << "\n";
                page = psuName + ", " +
                       rawdata.substr(rawdata.find("page-1"), page1Size);
                ofpsu << page;
                ofpsu << "\n";
                page = psuName + ", " +
                       rawdata.substr(rawdata.find("page-2"), page2Size);
                ofpsu << page;
                ofpsu << "\n";

                ofpsu.close();
                return;
            }
            else
            {
                std::cerr << "Fail to create psu blackbox log file!"
                          << std::endl;
                continue;
            }
        }

        std::ofstream oftmp("/run/psu_blackbox_tmp.log", std::ios::out);
        if (oftmp.good())
        {
            bool replace = false;
            std::string page;
            std::string oldPage;
            while (std::getline(ifpsu, oldPage))
            {
                std::cout << oldPage << std::endl;
                if ((oldPage.find(psuName) != std::string::npos))
                {
                    std::cout << "find " << psuName << " page" << std::endl;
                    if (replace != true)
                    {
                        std::cout << "need to replace" << std::endl;
                        page = psuName + ", " + rawdata.substr(0, page0Size);
                        oftmp << page;
                        oftmp << "\n";
                        page =
                            psuName + ", " +
                            rawdata.substr(rawdata.find("page-1"), page1Size);
                        oftmp << page;
                        oftmp << "\n";
                        page =
                            psuName + ", " +
                            rawdata.substr(rawdata.find("page-2"), page2Size);
                        oftmp << page;
                        oftmp << "\n";
                        replace = true;
                    }
                    else
                    {
                        std::cout << "DO not need to replace" << std::endl;
                    }
                }
                else
                {
                    if ((replace != true) && (oldPage > psuName))
                    {
                        std::cout << "need to insert" << std::endl;
                        page = psuName + ", " + rawdata.substr(0, page0Size);
                        oftmp << page;
                        oftmp << "\n";
                        page =
                            psuName + ", " +
                            rawdata.substr(rawdata.find("page-1"), page1Size);
                        oftmp << page;
                        oftmp << "\n";
                        page =
                            psuName + ", " +
                            rawdata.substr(rawdata.find("page-2"), page2Size);
                        oftmp << page;
                        oftmp << "\n";
                        replace = true;
                    }
                    oftmp << oldPage;
                    oftmp << "\n";
                }
            }
            ifpsu.close();
            oftmp.close();
        }
        else
        {
            std::cerr << "Fail to create tmp psu blackbox log file!"
                      << std::endl;
            ifpsu.close();
            continue;
        }

        std::ofstream ofpsu(blackboxLogFie, std::ios::out);
        std::ifstream iftmp("/run/psu_blackbox_tmp.log", std::ios::in);
        std::string page;
        while (std::getline(iftmp, page))
        {
            ofpsu << page;
            ofpsu << "\n";
        }
        ofpsu.close();
        iftmp.close();
        break;
    }

    return;
}

void PSUStatus::updateBlackbox(void)
{
    // check status word and read blackbox
    if (false == blackboxGot)
    {
        std::string blackboxFlagFilePath =
            "/run/lock/" + psuName + "_blackbox.done";
        std::ifstream iFile(blackboxFlagFilePath.c_str());
        if (iFile.good())
        {
            iFile.close();
            blackboxGot = true;
        }
        else
        {
            blackboxGot = true;
            updateBlackboxRecord();
            std::ofstream oFile(blackboxFlagFilePath.c_str());
            if (oFile.good())
            {
                oFile.close();
            }
            else
            {
                std::cerr << "Failed to create " << blackboxFlagFilePath
                          << std::endl;
            }
            return;
        }
    }

    std::vector<uint16_t> blackboxReadCondition = {
        OUTPUT_OVER_VOLT_PROTECTION,
        OUTPUT_UNDER_VOLT_PROTECTION,
        OVER_TEMP_PROTECTION,
        OUTPUT_OVER_CURRENT_PROTECTION,
        FAN_FAULT,
        FAN_WARNING,
        INPUT_OVER_VOLT_PROTECTION,
        INPUT_UNDER_VOLT_PROTECTION,
        OVER_TEMP_WARNING,
        OUTPUT_OVER_CURRENT_POWER_WARNING,
        INPUT_WARNING,
        POWER_SUPPLY_OFF};

    // check statusword in blackbox read condition
    std::vector<uint16_t>::iterator it = find(
        blackboxReadCondition.begin(), blackboxReadCondition.end(), StatusWord);
    if (it != blackboxReadCondition.end())
    {
        updateBlackboxRecord();
        return;
    }
}

void PSUStatus::updateStatusWord(void)
{
    if (Present == psuStatusAbsent)
    {
        LastStatusWord = 0;
        return;
    }

    if (blackboxGot != true)
    {
        updateBlackbox();
    }

    if (StatusWord == LastStatusWord)
    {
        return;
    }
    LastStatusWord = StatusWord;

    EventData edValue = {};

    // for otrd-sensor-monitor, present bit is always 1
    edValue[PRESENCE_DETECTED] = {};
    if (MASK_BIT_PSU_STATUS_WORD_VIN_UV_FAULT & StatusWord)
    {
        edValue[INPUT_LOST_OR_OUT_OF_RANGE] = {};
    }

    if (POWER_SUPPLY_OFF == StatusWord)
    {
        psustatusInterface->set_property("EventData", edValue);
        psustatusInterface->set_property("StatusWord", StatusWord);
        return;
    }

    if (StatusWord & PSU_STATUS_VOUT_FAULT_MASK)
    {
        if (psuVoutStatus[psuName])
        {
            uint8_t ucVoutStatus = psuVoutStatus[psuName]->getValue();
            if (ucVoutStatus & PSU_STATUS_VOUT_FAULT_REGISTER_SUPPLY_FAIL)
            {
                //*uwPSStatus |= (0x01 << POWER_SUPPLY_OFFSET_FAILURE_DETECTED);
                edValue[FAILURE_DETECTED] = {};
            }
        }
    }

    if (StatusWord & PSU_STATUS_INPUT_FAULT_MASK)
    {
        if (psuInputStatus[psuName])
        {
            uint8_t ucInputStatus = psuInputStatus[psuName]->getValue();
            if (ucInputStatus & PSU_STATUS_INPUT_FAULT_REGISTER_SUPPLY_FAIL)
            {
                //*uwPSStatus |= (0x01 << POWER_SUPPLY_OFFSET_FAILURE_DETECTED);
                edValue[FAILURE_DETECTED] = {};
            }
            else if (ucInputStatus &
                     PSU_STATUS_INPUT_FAULT_REGISTER_PREDICTIVE_FAIL)
            {
                //*uwPSStatus |= (0x01 <<
                // POWER_SUPPLY_OFFSET_PREDICTIVE_FAILURE);
                edValue[PREDICTIVE_FAILURE] = {};
            }
            else if (ucInputStatus & PSU_STATUS_INPUT_FAULT_REGISTER_AC_LOST)
            {
                //*uwPSStatus |= (0x01 << POWER_SUPPLY_OFFSET_INPUT_LOST);
                edValue[INPUT_LOST] = {};
            }
        }
    }

    if (StatusWord & PSU_STATUS_IOUT_FAULT_MASK)
    {
        if (psuIoutStatus[psuName])
        {
            uint8_t ucIoutStatus = psuIoutStatus[psuName]->getValue();
            if (ucIoutStatus & PSU_STATUS_IOUT_FAULT_REGISTER_SUPPLY_FAIL)
            {
                // *uwPSStatus |= (0x01 <<
                // POWER_SUPPLY_OFFSET_FAILURE_DETECTED);
                edValue[FAILURE_DETECTED] = {};
            }
            else if (ucIoutStatus &
                     PSU_STATUS_IOUT_FAULT_REGISTER_PREDICTIVE_FAIL)
            {
                //*uwPSStatus |= (0x01 <<
                // POWER_SUPPLY_OFFSET_PREDICTIVE_FAILURE);
                edValue[PREDICTIVE_FAILURE] = {};
            }
        }
    }

    if (StatusWord & PSU_STATUS_TEMPERATURE_FAULT_MASK)
    {
        if (psuOtpStatus[psuName])
        {
            uint8_t ucTempStatus = psuOtpStatus[psuName]->getValue();
            if (ucTempStatus &
                PSU_STATUS_TEMPERATURE_FAULT_REGISTER_SUPPLY_FAIL)
            {
                edValue[FAILURE_DETECTED] = {};
                //*uwPSStatus |= (0x01 << POWER_SUPPLY_OFFSET_FAILURE_DETECTED);
            }
            else if (ucTempStatus &
                     PSU_STATUS_TEMPERATURE_FAULT_REGISTER_PREDICTIVE_FAIL)
            {
                //*uwPSStatus |= (0x01 <<
                // POWER_SUPPLY_OFFSET_PREDICTIVE_FAILURE);
                edValue[PREDICTIVE_FAILURE] = {};
            }
        }
    }

    if (StatusWord & PSU_STATUS_FAN_FAULT_MASK)
    {
        if (psuFan12Status[psuName])
        {
            uint8_t ucFanStatus = psuFan12Status[psuName]->getValue();
            if (ucFanStatus & PSU_STATUS_FAN_FAULT_REGISTER_SUPPLY_FAIL)
            {
                edValue[FAILURE_DETECTED] = {};
                //*uwPSStatus |= (0x01 << POWER_SUPPLY_OFFSET_FAILURE_DETECTED);
            }
            else if (ucFanStatus &
                     PSU_STATUS_FAN_FAULT_REGISTER_PREDICTIVE_FAIL)
            {
                edValue[PREDICTIVE_FAILURE] = {};
                //*uwPSStatus |= (0x01 <<
                // POWER_SUPPLY_OFFSET_PREDICTIVE_FAILURE);
            }
        }
    }

    /*
        auto it = statusWordMap.find(StatusWord);
        if (it == statusWordMap.end())
        {
            std::cerr << "Status Word ：" << StatusWord << " is invalid\n";
            return;
        }

        std::cerr << "psu ipmi error: " << it->second.psustatusmessage << "\n";
        EventData edValue{{(uint8_t)it->second.ipmierror, {}}};
*/
    psustatusInterface->set_property("EventData", edValue);
    psustatusInterface->set_property("StatusWord", StatusWord);
    updateBlackbox();
}
void PSUStatus::setupRead(void)
{
    getPsuPresent();
    getStatusWord();
    handleResponse();
}
void PSUStatus::handleResponse(void)
{
    updateStatusWord();
    waitTimer.expires_from_now(boost::posix_time::milliseconds(pollMs));
    waitTimer.async_wait([&](const boost::system::error_code& ec) {
        if (ec == boost::asio::error::operation_aborted)
        {
            return;
        }
        setupRead();
    });
}

//设置电源模式到DBus
void PSUStatus::addPsuWorkMode2DBus(const std::string& filename)
{
    crmodePath = "/sys/class/hwmon/" + filename + "/cr_mode";
    onoffconfPath = "/sys/class/hwmon/" + filename + "/on_off_config";
    operationPath = "/sys/class/hwmon/" + filename + "/operation";

    psuModeInterface = objServer.add_interface(
        "/xyz/openbmc_project/State/" + psuName + "_WorkMode",
        "xyz.openbmc_project.State.WorkMode");

    // 1.设置电源模式回调函数
    auto setModeFuncHandler = [&](const std::string& newMode, const auto&) {
        //设置当前电源模式为normal/active/standby
        if (0 == newMode.compare(modeNormal) ||
            0 == newMode.compare(modeActive) ||
            0 == newMode.compare(modeStandby))
        {
            std::ofstream ref(crmodePath);
            if (!ref.good())
            {
                std::cerr << "Bad Write File\n";
                return -1;
            }
            ref << newMode;
            return 1;
        }
        std::cerr << "WorkMode value invalid\n";
        return -1;
    };

    // 2.获取电源模式回调函数
    auto getModeFuncHandler = [&](const auto&) {
        psuWorkMode.clear();
        std::ifstream modeFile(crmodePath);
        if (modeFile.good())
        {
            std::getline(modeFile, psuWorkMode);
            modeFile.close();
        }
        return psuWorkMode;
    };

    std::string defVal;
    psuModeInterface->register_property_rw(
        "WorkMode", defVal, sdbusplus::vtable::property_::emits_change,
        std::move(setModeFuncHandler), std::move(getModeFuncHandler));

    // 3.注册PowerCycle方法
    psuModeInterface->register_method("PowerCycle", [&]() {
        std::ofstream ref1(onoffconfPath);
        std::ofstream ref2(operationPath);
        if (!ref1.good() || !ref2.good())
        {
            std::cerr << "Bad Write File\n";
            return;
        }
        ref1 << PSU_CTRL_BY_COMMAND;
        ref2 << PSU_TURN_OFF;
    });

    psuModeInterface->initialize();
}

void PSUStatus::addPsuInputType2DBus(const std::string& filename)
{
    std::string inputTypePath;
    inputTypePath = "/sys/class/hwmon/" + filename + "/input_type";

    psuInputTypeIntface = objServer.add_interface(
        "/xyz/openbmc_project/State/" + psuName + "_InputType",
        "xyz.openbmc_project.State.InputType");

    psuInputTypeIntface->register_property_r(
        "InputType", std::string{}, sdbusplus::vtable::property_::emits_change,
        [inputTypePath](const auto&) {
            std::string psuInputType;
            std::ifstream typeFile(inputTypePath);
            if (typeFile.good())
            {
                std::getline(typeFile, psuInputType);
                typeFile.close();
            }
            return std::string(psuInputType);
        });
    psuInputTypeIntface->initialize();
}

//计算所有psu额定功率的总和
double PSUCombineStatus::calculationPsuAllRatedPower(void)
{
    std::vector<double> psuRatedPowerVec;
    double ratedPower = 0.0;
    // The number of PSU
    int psuSize = allPSUInfos.size();
    int oddOrEvenSize = round(psuSize / 2.0);
    for (const auto& it : allPSUInfos)
    {
        ratedPower = it.second->getPSURatedPower();
        psuRatedPowerVec.push_back(ratedPower);
        sort(psuRatedPowerVec.begin(), psuRatedPowerVec.end(), greater<>());
    }
    double powerCapacityWatts =
        accumulate(psuRatedPowerVec.begin(),
                   psuRatedPowerVec.begin() + oddOrEvenSize, 0.0);
    return powerCapacityWatts;
}

PSUCombineStatus::PSUCombineStatus(
    boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
    boost::container::flat_map<std::string, std::unique_ptr<PSUStatus>>
        psuStatus,
    std::map<std::string, std::string> psuPresentGpio,
    boost::container::flat_map<std::string, std::shared_ptr<PSUInfo>>
        allPSUInfos) :
    psuStatus(std::move(psuStatus)),
    allPSUInfos(std::move(allPSUInfos)), objServer(objectServer), waitTimer(io),
    psuPresentGpio(std::move(psuPresentGpio))

{
    std::string psuMismatchPath = "/xyz/openbmc_project/State/PSU_Mismatch";

    psuMismatchInterface =
        objServer.add_interface(psuMismatchPath, "com.otrd.Sensor.Status");

    EventData edValue{};
    psuMismatchInterface->register_property("EventData", edValue);
    psuMismatchInterface->initialize();
    psuMismatchDiagIntf =
        objectServer.add_interface(psuMismatchPath, "com.otrd.Sensor.DiagInfo");
    psuMismatchDiagIntf->register_property<std::string>(
        "AlertSource", "", sdbusplus::asio::PropertyPermission::readWrite);
    psuMismatchDiagIntf->register_property<std::string>(
        "DeviceSN", "", sdbusplus::asio::PropertyPermission::readWrite);
    psuMismatchDiagIntf->register_property<std::string>(
        "Location", "", sdbusplus::asio::PropertyPermission::readWrite);
    psuMismatchDiagIntf->register_property<std::string>(
        "MsgAddInfo", "", sdbusplus::asio::PropertyPermission::readWrite);
    psuMismatchDiagIntf->initialize();

    std::string psuLostPath = "/xyz/openbmc_project/State/PSU_Redundant";

    psuLostInterface =
        objServer.add_interface(psuLostPath, "com.otrd.Sensor.Status");

    psuLostInterface->register_property("EventData", edValue);
    psuLostInterface->initialize();

    psuMismatchSensorInterface = 
        objServer.add_interface(psuMismatchPath, "xyz.openbmc_project.Sensor.Value");
    psuRedSensorInterface =
        objServer.add_interface(psuLostPath, "xyz.openbmc_project.Sensor.Value");
    psuLostDiagIntf =
        objectServer.add_interface(psuLostPath, "com.otrd.Sensor.DiagInfo");
    psuLostDiagIntf->register_property<std::string>(
        "AlertSource", "", sdbusplus::asio::PropertyPermission::readWrite);
    psuLostDiagIntf->register_property<std::string>(
        "DeviceSN", "", sdbusplus::asio::PropertyPermission::readWrite);
    psuLostDiagIntf->register_property<std::string>(
        "Location", "", sdbusplus::asio::PropertyPermission::readWrite);
    psuLostDiagIntf->register_property<std::string>(
        "MsgAddInfo", "", sdbusplus::asio::PropertyPermission::readWrite);
    psuLostDiagIntf->initialize();

    std::string psuCapacityWattsPath = "/com/otrd/power/PowerCapacityWatts";

    psuCapacityWattsInterface = objServer.add_interface(
        psuCapacityWattsPath,
        "xyz.openbmc_project.Inventory.Item.PowerCapacityWatts");

    double ratedPowerValue = calculationPsuAllRatedPower();
    psuCapacityWattsInterface->register_property("PowerCapacityWatts",
                                                 ratedPowerValue);
    psuCapacityWattsInterface->initialize();

    setupRead();
}

PSUCombineStatus::~PSUCombineStatus()
{
    waitTimer.cancel();
}

// param out:
//  true - PresentRedundant Assert
//  false - PresentRedundant DeAssert
bool PSUCombineStatus::checkPresentRedundantLost(void)
{
    if (psuStatus.size() < psuPresentGpio.size())
    {
        return true;
    }
    for (const auto& it : psuStatus)
    {
        //不在位
        if (it.second->Present == psuStatusAbsent)
        {
            if (it.second->Present != LastPresent[it.first])
            {
                LastPresent[it.first] = it.second->Present;
            }
            return true;
        }
        LastPresent[it.first] = it.second->Present;
    }
    return false;
}

// param out:
//  true - ACLOSTRedundant Assert
//  false - ACLOSTRedundant DeAssert
bool PSUCombineStatus::checkACRedundantLost(void)
{
    if (psuStatus.size() < psuPresentGpio.size())
    {
        return true;
    }
    for (const auto& it : psuStatus)
    {
        // AC LOST 输入电源线拔出、输入电压过低
        if ((it.second->StatusWord & INPUT_UNDER_VOLT_PROTECTION) ||
            (it.second->StatusWord & INPUT_OVER_VOLT_PROTECTION) ||
            (it.second->StatusWord & OUTPUT_OVER_VOLT_PROTECTION) ||
            (it.second->StatusWord & OUTPUT_UNDER_VOLT_PROTECTION) ||
            (it.second->StatusWord & OVER_TEMP_PROTECTION) ||
            (it.second->StatusWord & OUTPUT_OVER_CURRENT_PROTECTION) ||
            (it.second->StatusWord & FAN_FAULT))
        {
            if (it.second->StatusWord != lastStatusWord[it.first])
            {
                lastStatusWord[it.first] = it.second->StatusWord;
            }
            return true;
        }
        lastStatusWord[it.first] = it.second->StatusWord;
    }

    return false;
}

void PSUCombineStatus::updateRedundant(void)
{
    if ((true == checkPresentRedundantLost()) ||
        (true == checkACRedundantLost()))
    {
        // PSU Redundant Assert
        EventData edValue{{0x01, {}}}; // REDUNDANCY_LOST
        psuLostInterface->set_property("EventData", edValue);
    }
    else
    {
        // PSU Redundant Deassert
        EventData edValue{};
        psuLostInterface->set_property("EventData", edValue);
    }

    return;
}

// param out:
//  true - Mismatch Assert
//  false - Mismatch DeAssert
bool PSUCombineStatus::checkMismatch(void)
{
    if (allPSUInfos.size() < 2)
    {
        return false;
    }

    std::set<string> psuModels;
    std::string model = "";

    //只有获取到2个以上电源信息才进行比较
    for (const auto& it : allPSUInfos)
    {
        model = it.second->getPSUModel();
        if (!model.empty())
        {
            psuModels.insert(model);
        }
    }

    if (psuModels.size() > 1)
    {
        // PSU Mismatch Assert
        return true;
    }

    std::set<string> psuManus;
    std::string manu = "";

    for (const auto& it : allPSUInfos)
    {
        manu = it.second->getPSUManu();
        if (!manu.empty())
        {
            psuManus.insert(manu);
        }
    }

    if (psuManus.size() > 1)
    {
        //PSU Mismatch Assert
        return true;
    }

    return false;
}

void PSUCombineStatus::updateMismatch(void)
{
    // 将不同型号的电源线和电源模块拔出，SEL未记录电源不匹配的告警解除日志，不在位时要解除告警
    if ((true == checkMismatch()) && (false == checkPresentRedundantLost()))
    {
        // PSU Mismatch Assert
        EventData edValue{{0x06, {}}}; // PSU_MISMATCH
        psuMismatchInterface->set_property("EventData", edValue);
    }
    else
    {
        // PSU Mismatch Deassert
        EventData edValue{};
        psuMismatchInterface->set_property("EventData", edValue);
    }
    return;
}

void PSUCombineStatus::setupRead(void)
{
    updateRedundant();
    updateMismatch();

    waitTimer.expires_from_now(boost::posix_time::milliseconds(psuPollMs));
    waitTimer.async_wait([&](const boost::system::error_code& ec) {
        if (ec == boost::asio::error::operation_aborted)
        {
            return;
        }

        setupRead();
    });
}

VR_Version::VR_Version(const std::string& bus, const std::string& address,
                       sdbusplus::asio::object_server& objectServer,
                       const std::string& vrName) :
    objServer(objectServer),
    vrName(vrName)
{
    std::string filename;
    std::filesystem::path hwParentPath;
    hwParentPath = "/sys/bus/i2c/devices/" + bus + "-" + address + "/hwmon";
    if (std::filesystem::exists(hwParentPath))
    {
        for (auto& str : std::filesystem::directory_iterator(hwParentPath))
        {
            filename = str.path().filename();
        }
    }
    hwMonitorPath =
        "/sys/bus/i2c/devices/" + bus + "-" + address + "/hwmon/" + filename;

    std::cerr << "VR: " << vrName << ", hwmon: " << hwMonitorPath << std::endl;

    std::string softVersionPath = "/xyz/openbmc_project/software/" + vrName;
    std::string softVersionInterface = "xyz.openbmc_project.Software.Version";

    VRSoftVersionInterface =
        objServer.add_interface(softVersionPath, softVersionInterface);

    std::string version = "null";
    VRSoftVersionInterface->register_property("Version", version);
    std::string purpose =
        "xyz.openbmc_project.Software.Version.VersionPurpose.VR";
    VRSoftVersionInterface->register_property("Purpose", purpose);
    VRSoftVersionInterface->initialize();

    setupRead();
}

VR_Version::~VR_Version()
{
    // TODO
}

std::string VR_Version::getMotherBoardPartNumber(void)
{
    std::variant<std::string> request;

    try
    {
        auto bus = sdbusplus::bus::new_default();
        auto method =
            bus.new_method_call("xyz.openbmc_project.FruDevice",
                                "/xyz/openbmc_project/FruDevice/MB_FRU",
                                "org.freedesktop.DBus.Properties", "Get");
        method.append("xyz.openbmc_project.FruDevice", "BOARD_PART_NUMBER");
        auto msg = bus.call(method);
        msg.read(request);
    }
    catch (const sdbusplus::exception::SdBusError& ex)
    {
        return "";
    }

    return (std::get<std::string>(request));
}

void VR_Version::setupRead(void)
{
    std::string version;
    std::string versionPath = hwMonitorPath + "/firmware_version";
    std::ifstream fileStream(versionPath);

    std::getline(fileStream, version);
    std::string partnumber = getMotherBoardPartNumber();
    version = partnumber + "_" + version;
    VRSoftVersionInterface->set_property("Version", version);
}